/*
 * Copyright (c) 2011 by Chances.
 * $CVSHeader$
 * $Author$
 * $Date$
 * $Revision$
 */
package mxmf.utils;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.vfs.FileSystemException;
import org.apache.commons.vfs.provider.GenericFileName;
import org.apache.commons.vfs.provider.ftp.FtpFileNameParser;

import com.enterprisedt.net.ftp.FTPConnectMode;
import com.enterprisedt.net.ftp.FTPException;
import com.enterprisedt.net.ftp.FileTransferClient;

/**
 * Class comments.
 *
 * @author <a href="mailto:libf@chances.com.cn">libf</a>
 */
public class FtpUtils {
    private static final Log logger = LogFactory.getLog(FtpUtils.class);
    private static final int BUFFER_SIZE = 1024 * 10;
    private static final String ANONYMOUS_USER = "anonymous";

    private FtpUtils() {
    }

    /**
     * 下载FTP文件到本地目录.
     * 
     * @param sourceURL
     * @param destPath
     * @throws IOException 
     * @throws FTPException 
     * @throws Exception
     */
    public static void download(String sourceURL, String destPath)
            throws FTPException, IOException {
        FileTransferClient client = null;

        String sourceFilePath = getRemoteFilePath(sourceURL);
        String targetFilePath = FileNameUtils.getPath(destPath);

        // 建立连接
        client = connect(sourceURL);
        // 创建本地目录
        File targetFolder = new File(targetFilePath);
        if (!targetFolder.exists()) {
            targetFolder.mkdirs();
        }

        try (InputStream inStream = client.downloadStream(sourceFilePath);
                OutputStream outStream = new FileOutputStream(destPath)) {
            write(inStream, outStream);

        } finally {
            close(client);
        }

    }

    public static void write(InputStream inStream, OutputStream outStream) throws IOException {
        if (inStream == null) {
            throw new IOException("Input stream is null.");
        }

        if (outStream == null) {
            throw new IOException("Output stream is null.");
        }

        final byte[] buffer = new byte[BUFFER_SIZE];

        while (true) {
            final int nread = inStream.read(buffer);

            if (nread < 0) {
                break;
            }

            outStream.write(buffer, 0, nread);
        }
    }

    /**
     * 建立FTP连接.
     * 
     * @param ftpURL
     * @return
     * @throws FTPException 
     * @throws IOException 
     */
    public static FileTransferClient connect(String ftpURL) throws FTPException, IOException {
        FtpFileNameParser parser = (FtpFileNameParser) FtpFileNameParser.getInstance();
        GenericFileName fileName = null;
        try {
            fileName = (GenericFileName) parser.parseUri(null, null, ftpURL);
        } catch (FileSystemException ex) {
            logger.error("Create ftp client error,ftpURL=" + ftpURL, ex);
            throw ex;
        }

        FileTransferClient client = new FileTransferClient();

        client.setRemoteHost(fileName.getHostName());
        client.setRemotePort(fileName.getPort());

        // 匿名用户
        if (StringUtils.isBlank(fileName.getUserName())) {
            client.setUserName(ANONYMOUS_USER);
        } else {
            client.setUserName(fileName.getUserName());
            client.setPassword(fileName.getPassword());
        }

        client.getAdvancedSettings().setControlEncoding("GBK");

        client.getAdvancedFTPSettings().setConnectMode(FTPConnectMode.PASV);

        client.getAdvancedFTPSettings().setRetryCount(3);
        client.getAdvancedFTPSettings().setAutoPassiveIPSubstitution(true);

        try {
            logger.debug("Connecting to " + client.getRemoteHost());
            client.connect();
            logger.debug("Connected to " + client.getRemoteHost());
        } catch (IOException ex) {
            logger.error("Connect and login error,host " + fileName.getHostName(), ex);
            throw ex;
        }

        return client;
    }

    /**
     * 根据远程访问连接获取文件路径.
     * 
     * @param remoteURI
     * @return
     */
    public static String getRemoteFilePath(String remoteURI) {
        FtpFileNameParser parser = (FtpFileNameParser) FtpFileNameParser.getInstance();
        try {
            GenericFileName fileName = (GenericFileName) parser.parseUri(null, null, remoteURI);

            return fileName.getPathDecoded();
        } catch (FileSystemException ex) {
            logger.error(ex);
            return "";
        }
    }

    /**
     * 关闭FTP连接.
     * 
     * @param client
     */
    private static void close(FileTransferClient client) {
        if (client == null) {
            return;
        }

        logger.debug("Disconnecting to " + client.getRemoteHost());
        try {
            client.disconnect();
            logger.debug("Disconnected to " + client.getRemoteHost());
        } catch (Exception ex) {
            logger.error("Disconnect to " + client.getRemoteHost() + " error.", ex);
        }
    }

}
